package com.jl;

import org.elasticsearch.search.sort.SortBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHitSupport;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

/**
 * es mapper实现
 *
 * @param <M>
 * @param <E>
 */
public class JLElasticsearchServiceImpl<M extends ElasticsearchRepository, E> {

    @Autowired
    private ElasticsearchOperations operations;

    @Autowired
    protected M baseMapper;

    /**
     * id查询是否存在
     *
     * @param id
     * @return
     */
    public boolean existsById(String id) {
        return baseMapper.existsById(id);
    }

    /**
     * id查询
     *
     * @param id
     * @return
     */
    public E getById(String id) {
        Class<E> entity = getEntity();
        return operations.get(id, entity, getIndex(entity));
    }

    /**
     * 数量
     *
     * @param query
     * @return
     */
    public long count(NativeSearchQuery query) {
        Class<E> entity = getEntity();
        return operations.count(query, entity, getIndex(entity));
    }

    /**
     * 对象
     *
     * @param query
     * @return
     */
    public E get(NativeSearchQuery query) {
        List<E> list = list(query);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 集合
     *
     * @param query
     * @return
     */
    public List<E> list(NativeSearchQuery query) {
        //允许数据超过一万条
        query.setTrackTotalHits(true);
        Class<E> entity = getEntity();
        SearchHits<E> searchHits = operations.search(query, entity, getIndex(entity));
        List<SearchHit<E>> searchHits1 = searchHits.getSearchHits();
        List<E> result = new ArrayList<>();
        for (SearchHit<E> tSearchHit : searchHits1) {
            result.add(tSearchHit.getContent());
        }
        return result;
    }

    /**
     * 分页
     *
     * @param query
     * @return
     */
    public Page<E> page(NativeSearchQuery query, Pageable pageable) {
        Class<E> entity = getEntity();
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
                .withQuery(query.getQuery())
                .withPageable(pageable);
        List<SortBuilder> elasticsearchSorts = query.getElasticsearchSorts();
        for (SortBuilder elasticsearchSort : elasticsearchSorts) {
            nativeSearchQueryBuilder.withSort(elasticsearchSort);
        }
        NativeSearchQuery build = nativeSearchQueryBuilder.build();
        //允许数据超过一万条
        build.setTrackTotalHits(true);
        SearchHits<E> searchHits = operations.search(build, entity, getIndex(entity));
        AggregatedPage<SearchHit<E>> page = SearchHitSupport.page(searchHits, query.getPageable());
        return (Page<E>) SearchHitSupport.unwrapSearchHits(page);
    }

    /**
     * 保存
     *
     * @param entity
     * @return
     */
    public E save(E entity) {
        baseMapper.save(entity);
        return entity;
    }

    /**
     * 批量保存
     *
     * @param entitys
     * @return
     */
    public Iterable<E> save(Iterable<E> entitys) {
        baseMapper.saveAll(entitys);
        return entitys;
    }

    /**
     * id删除
     *
     * @param id
     */
    public void remove(String id) {
        baseMapper.deleteById(id);
    }

    /**
     * id删除
     *
     * @param ids
     */
    public void remove(Iterable<String> ids) {
        baseMapper.deleteAll(ids);
    }

    /**
     * 删除全部
     */
    public void remove() {
        baseMapper.deleteAll();
    }

    private Class<E> getEntity() {
        Class<E> entityClass = (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        return entityClass;
    }

    private IndexCoordinates getIndex(Class<E> entity) {
        Document document = JLReflect.ClassReflect.getAnnotate(entity, Document.class);
        return IndexCoordinates.of(JLStringTools.humpToLine(document.indexName()));
    }
}
